package com.pruebas.physics.dragableworldgravity;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import com.pruebas.physics.common.Circle;
import com.pruebas.physics.common.SimpleMomentum;
import com.pruebas.physics.common.SurfaceMapper;


import android.opengl.GLSurfaceView;
import android.opengl.GLU;

public class DragableWorldGravityRenderer implements GLSurfaceView.Renderer {
	private SurfaceMapper surfaceMapper;
	
	private static final int definition = 60;
	private Circle world;
	private Circle ball;
	
	private static final float gravity = -0.2f;
	private static final float defaultTimeDelta = 0.5f;
	private float timeDelta = defaultTimeDelta;
	
	private float ballLastSpeed = 0f;
	private float ballLastXPos = 0f;
	private float ballLastYPos = 0f;
	
	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		// Set the background frame color
        gl.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
        // initialize the rectangle vertex array
        initShapes();
        // Enable use of vertex arrays
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    }
    
    public void onDrawFrame(GL10 gl) {
    	// Redraw background color
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
        
        SimpleMomentum ballMomentum = this.CalculateNewCoordinates(ballLastXPos, ballLastYPos, ballLastSpeed, timeDelta); 
	    float ballXPos = ballMomentum.getxPos();
        float ballYPos = ballMomentum.getyPos();
	        
	    ballLastSpeed = ballMomentum.getSpeed();
	    ballLastXPos = ballXPos;
	    ballLastYPos = ballYPos;
        
        //Ball
        gl.glPushMatrix();
        gl.glColor4f(0f, 1f, 1f, 0.0f);
        gl.glTranslatef(ballXPos - ball.getInitialX(), ballYPos - ball.getInitialY(), 0);
        ball.draw(gl);
        gl.glPopMatrix();
        
        //world
        gl.glPushMatrix();
        gl.glColor4f(1f, 0f, 1f, 0.0f);
        world.draw(gl);
        gl.glPopMatrix();
    }
    
    public void onSurfaceChanged(GL10 gl, int width, int height) {
    	this.surfaceMapper = new SurfaceMapper(width, height, 5f);
    	
        gl.glViewport(0, 0, width, height);
        
        // make adjustments for screen ratio
        gl.glMatrixMode(GL10.GL_PROJECTION);        // set matrix to projection mode
        gl.glLoadIdentity();                        // reset the matrix to its default state
        gl.glFrustumf(-this.surfaceMapper.getRatio(), this.surfaceMapper.getRatio(), -1, 1, 1f, 10);  // apply the projection matrix
        
        gl.glMatrixMode(GL10.GL_PROJECTION);
        gl.glLoadIdentity();
        // Set GL_MODELVIEW transformation mode
        GLU.gluOrtho2D(gl,
        		-this.surfaceMapper.getMagicX(), this.surfaceMapper.getMagicX(),
        		-this.surfaceMapper.getMagicY(), this.surfaceMapper.getMagicY());
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        gl.glLoadIdentity(); // reset the matrix to its default state
        // When using GL_MODELVIEW, you must set the view point
        GLU.gluLookAt(gl, 0, 0, -1f, 0f, 0f, 0f, 0f, 1f, 0.0f);

    }
    
    public Boolean isTouchingTheBall(float x, float y){
    	float[] mappedCoords = this.surfaceMapper.mapCoordinates(x, y);
    	float mappedX = mappedCoords[0];
    	float mappedY = mappedCoords[1];
    	
    	float distanceX = this.ballLastXPos - mappedX; 
		float distanceY = this.ballLastYPos - mappedY;
		float distance = (float)Math.sqrt((distanceX * distanceX) + (distanceY * distanceY)); 
		return (distance <= this.ball.getRadius());
    }
    
    public void setBallPosition(float x, float y){
    	float[] mappedCoords = this.surfaceMapper.mapCoordinates(x, y);
    	float mappedX = mappedCoords[0];
    	float mappedY = mappedCoords[1];
    	
    	SimpleMomentum ballMomentum = this.CalculateNewCoordinates(mappedX, mappedY, 0, 0);
    	this.ballLastXPos = ballMomentum.getxPos();
    	this.ballLastYPos = ballMomentum.getyPos();
    	this.ballLastSpeed = ballMomentum.getSpeed();
    }
    
    public void stopTime() {
		this.timeDelta = 0f;
		this.ballLastSpeed = 0f;
	}
    
    public void resumeTime() {
		this.timeDelta = defaultTimeDelta;
	}
    
    public boolean isTimeStopped(){
    	return this.timeDelta == 0f;
    }
    
    private void initShapes(){
    	this.ballLastXPos = -2.5f;
    	this.ballLastYPos = 3f;
    	this.ball = new Circle(0.5f, definition, ballLastXPos, ballLastYPos);
    	this.world = new Circle(1.5f, definition, 1f, -2f);
    }
    
    private SimpleMomentum CalculateNewCoordinates(float lastXPos, float lastYPos, float lastSpeed, float elapsedTime){
    	float distanceX = lastXPos - world.getInitialX();
        float distanceY = lastYPos- world.getInitialY();
        double xyAngle = Math.atan(distanceX/distanceY);
        
        float ballSpeed = lastSpeed + gravity * elapsedTime;
        
        float distance = (float)Math.sqrt((distanceX * distanceX) + (distanceY * distanceY));
        float newDistance = distance + ballSpeed * elapsedTime;
        
        if(newDistance <= world.getRadius() + ball.getRadius()){
        	ballSpeed *= -0.5;
        	newDistance = world.getRadius() + ball.getRadius();
        }
        
        float ballXPos = (float)(Math.sin(xyAngle) * newDistance);
        float ballYPos = (float)(Math.cos(xyAngle) * newDistance);
        if(distanceY < 0){
        	ballXPos *= -1f;
        	ballYPos *= -1f;
        }	        
        ballXPos += world.getInitialX();
    	ballYPos += world.getInitialY();
    	
    	SimpleMomentum ballMomentum = new SimpleMomentum(ballXPos, ballYPos, ballSpeed);
    	return ballMomentum;
    }
    
}